#include "StdAfx.h"
#include "FMDBRecordSet.h"
#include <assert.h>
#include "ErrorCheck.h"
#include <utility>
#include "OCIConstDefine.h"
#include <afx.h>



FMDBRecordSet::FMDBRecordSet(void)
{
	m_pStmt=NULL;
	m_CacheSize=1;
	m_pErr=NULL;
	m_CacheRowNumber=0;
	m_CacheEndRowNumber=0;
	m_bstmtRelease=true;
	m_bIsScrollable=true;
	m_bIsready=false;
	m_bAuto=true;//default we use manually maintain storage to increase performance
	m_iColCount=0;
	m_pColumns=NULL;
	m_pIOVColumns=NULL;
}


FMDBRecordSet::~FMDBRecordSet(void)
{
	//release statement
	if (m_pStmt)
	{
		if (m_bstmtRelease)
		{
			CheckErr(m_pErr,OCIStmtRelease(m_pStmt,m_pErr,NULL,0,OCI_DEFAULT));//ocistmt is allocate by prepare
		}
		else
		{
			CheckErr(m_pErr,OCIHandleFree(m_pStmt,OCI_HTYPE_STMT));//oci stmt is allocate by ocihandleallocate
		}
	}


	//release resource
	if (m_bAuto)//only release auto mode, manual mode the caller should release columns
	{
		for(std::map<ub4,FMDBColumn*>::iterator iter= m_ColumnMapByPos.begin();iter!=m_ColumnMapByPos.end();iter++)
		{
			delete iter->second;
		}
		delete[] m_pColumns;

		for(std::map<ub4,FMDBIOVColumn*>::iterator iter= m_IOVColumnMapByPos.begin();iter!=m_IOVColumnMapByPos.end();iter++)
		{
			delete iter->second;
		}
		delete[] m_pIOVColumns;

		for(std::map<ub4,ColumnInfo*>::iterator iter= m_ColInfoMapByPos.begin();iter!=m_ColInfoMapByPos.end();iter++)
		{
			delete iter->second;
		}
	}
}

//note:caller manage column
void FMDBRecordSet::AddColumn( FMDBColumn *col,ub4 colIndex )
{
	assert(col!=NULL);
	if (col)
	{
		m_ColumnMapByPos.insert(std::pair<ub4,FMDBColumn*>(colIndex,col));
	}

}

void FMDBRecordSet::AddColumn( FMDBIOVColumn *col,ub4 colIndex )
{
	assert(col!=NULL);
	if (col)
	{
		m_IOVColumnMapByPos.insert(std::pair<ub4,FMDBIOVColumn*>(colIndex,col));
	}
}

int FMDBRecordSet::First()
{
	ResetIOVColumnValue();
	//fetch data and fill the cache
	sb4 status;
	//note:non-scrollable cursor doesn't support first, so if non-scrollable cursor call first equal to Next()
	if (m_bIsScrollable)
	{
		status=OCIStmtFetch2(m_pStmt,m_pErr,m_CacheSize,OCI_FETCH_FIRST,0,OCI_DEFAULT);
	}
	else
	{
		status=OCIStmtFetch2(m_pStmt,m_pErr,m_CacheSize,OCI_FETCH_NEXT,0,OCI_DEFAULT);
	}

	if((status==OCI_SUCCESS) ||(status==OCI_NO_DATA))
	{
		if (status==OCI_SUCCESS)
		{
			m_CacheEndRowNumber=m_CacheSize;//full fill the cache
		} 
		else if (status==OCI_NO_DATA)
		{
			//row number is smaller than cache
			CheckErr(m_pErr,OCIAttrGet(m_pStmt,OCI_HTYPE_STMT,&m_CacheEndRowNumber,NULL,OCI_ATTR_ROWS_FETCHED,m_pErr));
			if (m_CacheEndRowNumber==0)//be the end of recordset
			{
				return FMSQL_EOF;//EOF;
			}
		}
		m_CacheRowNumber=1;

		return FMSQL_OK;
	}
	else
	{
		//some error happened
		CheckErr(m_pErr,status);
		return FMSQL_FAILED;
	}
}

void FMDBRecordSet::SetCacheSize( int val )
{
	m_CacheSize=val;

	//reallocate columns cache size
	for (std::map<ub4,FMDBColumn*>::iterator iter=m_ColumnMapByPos.begin();iter!=m_ColumnMapByPos.end();iter++)
	{
		iter->second->SetStorageBySize(m_CacheSize);
	}

	//reallocate IOV columns cache size
	for (std::map<ub4,FMDBIOVColumn*>::iterator iter=m_IOVColumnMapByPos.begin();iter!=m_IOVColumnMapByPos.end();iter++)
	{
		iter->second->RemoveStorage();
		iter->second->SetStorage(m_CacheSize,iter->second->GetDataSize());
	}
}

int FMDBRecordSet::GetRowCount()
{
	//note:non-scrollable cursor doesn't support GetRowCount
	if (!m_bIsScrollable)
	{
		return -1;
	}

	//fetch data,because of we use fetch last, so it ignores cache size and only fetch the last row
	sb4 status;
	int RowCount=-1;
	status=OCIStmtFetch2(m_pStmt,m_pErr,m_CacheSize,OCI_FETCH_LAST,0,OCI_DEFAULT);
	if((status==OCI_SUCCESS) ||(status==OCI_NO_DATA))
	{
		//note:we use current row number as row count
		CheckErr(m_pErr,OCIAttrGet(m_pStmt,OCI_HTYPE_STMT,&RowCount,NULL,OCI_ATTR_CURRENT_POSITION,m_pErr));	
		return RowCount;
	}
	else
	{
		//some error happened
		CheckErr(m_pErr,status);
		return -1;
	}
}

int FMDBRecordSet::Next()
{
	m_CacheRowNumber++;
	
	if (m_CacheRowNumber==m_CacheEndRowNumber+1 && m_CacheEndRowNumber<m_CacheSize)
	{
		return FMSQL_EOF;//EOF;//it's the end of recordset
	}

	if (m_CacheRowNumber>m_CacheEndRowNumber)//out of cache
	{
		ResetIOVColumnValue();

		//fetch data and fill the cache
		sb4 status;
		status=OCIStmtFetch2(m_pStmt,m_pErr,m_CacheSize,OCI_FETCH_NEXT,0,OCI_DEFAULT);
		if((status==OCI_SUCCESS) ||(status==OCI_NO_DATA))
		{
			if (status==OCI_SUCCESS)
			{
				m_CacheEndRowNumber=m_CacheSize;//full fill the cache
			} 
			else if (status==OCI_NO_DATA)
			{
				//row number is smaller than cache
				CheckErr(m_pErr,OCIAttrGet(m_pStmt,OCI_HTYPE_STMT,&m_CacheEndRowNumber,NULL,OCI_ATTR_ROWS_FETCHED,m_pErr));
				if (m_CacheEndRowNumber==0)//be the end of recordset
				{
					return FMSQL_EOF;//EOF;
				}
			}
			m_CacheRowNumber=1;
			return FMSQL_OK;
		}
		else
		{
			//some error happened
			CheckErr(m_pErr,status);
			return FMSQL_FAILED;
		}
	}
	return FMSQL_OK;
}

//note:GetValue function get raw data from DB, only useful when you know what you are doing!!
void * FMDBRecordSet::GetValue( int ColIndex )
{
	//check if the column index exists
	std::map<ub4,ColumnInfo*>::const_iterator iterInfo = m_ColInfoMapByPos.find(ColIndex);
	if (iterInfo==m_ColInfoMapByPos.end())
	{
		return NULL;//if the column doesn't exist then return nothing
	}

	if(iterInfo->second->bIsIOVCol)//this column is IOV column
	{
		FMDBIOVColumn *pCol=NULL;
		std::map<ub4,FMDBIOVColumn*>::const_iterator iter=m_IOVColumnMapByPos.find(ColIndex);
		if (iter==m_IOVColumnMapByPos.end())
		{
			return NULL;
		}

		pCol=iter->second;

		return ((OCIIOV*)pCol->GetStorage())[m_CacheRowNumber-1].bfp;
	}
	else//this column is simple column
	{
		FMDBColumn *pCol=nullptr;
		std::map<ub4,FMDBColumn*>::const_iterator iter=m_ColumnMapByPos.find(ColIndex);
		if (iter==m_ColumnMapByPos.end())
		{
			return NULL;
		}
		
		pCol=iter->second;

		switch(pCol->GetType())
		{
		case SQLT_INT:
			return &(((int*)pCol->GetStorage())[m_CacheRowNumber-1]);

		case SQLT_BDOUBLE:
			return &(((double*)pCol->GetStorage())[m_CacheRowNumber-1]);

		case SQLT_NUM://return OCINumber, caller should convert it to desired type
		case SQLT_VNU:
			return &(((OCINumber*)pCol->GetStorage())[m_CacheRowNumber-1]);
 
		default:
			throw "unimplemented data type";
		}
	}
}

//note:GetValue function get raw data from DB, only useful when you know what you are doing!!
void * FMDBRecordSet::GetValue( CString ColName )
{
	//check if the column name exists
	std::map<CString,ColumnInfo*>::const_iterator iter = m_ColInfoMapByName.find(ColName);
	if (iter==m_ColInfoMapByName.end())
	{
		return NULL;//if the column doesn't exist then return nothing
	}

	return GetValue(iter->second->Position);
}

int FMDBRecordSet::GetColumnCount()
{
	if (m_bAuto)
	{
		CheckErr(m_pErr, OCIAttrGet((void *)m_pStmt, OCI_HTYPE_STMT, (void *)&m_iColCount,	(ub4 *)0, OCI_ATTR_PARAM_COUNT, m_pErr));
	} 
	else
	{
		m_iColCount=(int)(m_ColumnMapByPos.size()+m_IOVColumnMapByPos.size());
	}
	return m_iColCount;

}

void FMDBRecordSet::IsReady( bool val )
{
	m_bIsready=val;

	//if automatically get columns, this is the chance
	if (m_bAuto)
	{
		if (val==false)
		{
			//clear all resource used by this object
			delete[] m_pColumns;
			delete[] m_pIOVColumns;
			m_iColCount=0;
			m_pColumns=NULL;
			m_pIOVColumns=NULL;
			return;
		}

		sb4 parm_status;
		ub4 ColCounter=1;		//column counter note:in theory, this is the column position value
		OCIParam *colhd = NULL;	//column handle
		ub2 type = 0;			//column data type
		ub4 MaxSize=0;			//column data max size
		text *col_name=NULL;	//column name
		ub4 col_name_len=0;		//length of column name(bytes)
		ub4 colID=0;			//column ID in column array
		ub4 colIOVID=0;			//column ID in IOV column array
		//ub4 colPos=0;			//column position
		ColumnInfo *pColInfo=NULL;

		//Get parameter for column 1
		parm_status=OCIParamGet((void *)m_pStmt, OCI_HTYPE_STMT, m_pErr, (void **)&colhd, ColCounter);
		//Go through the column list and retrieve the data type of each column. start from pos = 1
		while (parm_status==OCI_SUCCESS) 
		{
			//Get data-type of column i 
			CheckErr(m_pErr, OCIAttrGet((void *)colhd, OCI_DTYPE_PARAM,(void *)&type, (ub4 *)0, OCI_ATTR_DATA_TYPE, m_pErr));
			//Get name of column i 
			CheckErr(m_pErr, OCIAttrGet((void *)colhd, OCI_DTYPE_PARAM,(dvoid**) &col_name,(ub4 *) &col_name_len, OCI_ATTR_NAME,m_pErr ));
			//Get max data size of column i 
			CheckErr(m_pErr, OCIAttrGet((void *)colhd, OCI_DTYPE_PARAM,(dvoid**) &MaxSize,(ub4 *)0, OCI_ATTR_DATA_SIZE,m_pErr ));

			//Get position column i 
			//note: this value in theory is the same value as ColCounter, so we don't use this statement to increase performance
			//CheckErr(m_pErr, OCIAttrGet((void *)colhd, OCI_DTYPE_PARAM,(dvoid**) &colPos,(ub4 *)0, OCI_ATTR_POSITION,m_pErr ));

			////stupid data type convert, oracle do not support CLOB as binding data type, we have to change it to long type
			//if (type==SQLT_CLOB)
			//{
			//	type=SQLT_LNG;
			//}

			pColInfo=new ColumnInfo();
			pColInfo->ColumnName=(TCHAR*)col_name;
			pColInfo->DataType=type;
			pColInfo->MaxSize=MaxSize;
			pColInfo->Position=ColCounter;

			//auto allocate columns
			switch(type)
			{
			case SQLT_NUM:
				pColInfo->DataType=SQLT_VNU;
				pColInfo->bIsIOVCol=false;
				pColInfo->ColumnID=colID;
				break;

			case SQLT_STR:
			case SQLT_CHR:
			case SQLT_CLOB:
			case SQLT_LNG:
				//these types I design to use IOV to save memory,also we can use normal define except LNG and CLOB
				pColInfo->bIsIOVCol=true;
				pColInfo->ColumnID=colIOVID;
				break;

			case SQLT_BIN://note:it's strongly recommended do not use binary type of fields.we can find a replacement anyway.
				pColInfo->bIsIOVCol=true;
				pColInfo->ColumnID=colIOVID;
				break;

			default:
				//note: 
				ASSERT(false);//,_T("unimplemented SQL data type for FMDBRecordSetAuto:IsReady "));
				return;
				break;
			}

			m_ColInfoMapByPos.insert(std::pair <ub4,ColumnInfo*>(ColCounter,pColInfo));
			m_ColInfoMapByName.insert(std::pair <CString,ColumnInfo*>(pColInfo->ColumnName,pColInfo));


			colID++;
			colIOVID++;
			ColCounter++;
			//Get parameter for next column
			parm_status=OCIParamGet((void *)m_pStmt, OCI_HTYPE_STMT, m_pErr, (void **)&colhd, ColCounter);
		}

		//set columns array
		m_pColumns=new FMDBColumn*[colID];
		m_pIOVColumns=new FMDBIOVColumn*[colIOVID];

		//add columns from map to arrays 
		for (std::map<ub4,ColumnInfo*>::iterator iter=m_ColInfoMapByPos.begin();iter!=m_ColInfoMapByPos.end();iter++)
		{
			if (iter->second->bIsIOVCol)
			{
				m_pIOVColumns[iter->second->ColumnID]=new FMDBIOVColumn(iter->first,0,iter->second->MaxSize,iter->second->DataType);
				m_pIOVColumns[iter->second->ColumnID]->SetColumnInfo(*iter->second);
				AddColumn(m_pIOVColumns[iter->second->ColumnID],iter->second->Position);
			}
			else
			{				
				m_pColumns[iter->second->ColumnID]=new FMDBColumn(iter->first,0,iter->second->DataType);
				m_pColumns[iter->second->ColumnID]->SetColumnInfo(*iter->second);
				AddColumn(m_pColumns[iter->second->ColumnID],iter->second->Position);
			}
			
		}

		SetCacheSize(m_CacheSize);	//allocate storage
	}
}

ColumnInfo * FMDBRecordSet::GetColumnInfo( ub4 colIndex )
{
	std::map<ub4,ColumnInfo*>::const_iterator iter=m_ColInfoMapByPos.find(colIndex);
	if (iter!=m_ColInfoMapByPos.end())
	{
		return iter->second;
	}

	return NULL;
}

ColumnInfo * FMDBRecordSet::GetColumnInfo( CString colName )
{
	std::map<CString,ColumnInfo*>::const_iterator iter=m_ColInfoMapByName.find(colName);
	if (iter!=m_ColInfoMapByName.end())
	{
		return iter->second;
	}
	return NULL;
}

bool FMDBRecordSet::GetUInt64Value( CString ColName,unsigned __int64& val )
{
	//check if the column name exists
	std::map<CString,ColumnInfo*>::const_iterator iter = m_ColInfoMapByName.find(ColName);
	if (iter==m_ColInfoMapByName.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	return GetUInt64Value(iter->second->Position,val);
}

 bool FMDBRecordSet::GetUInt64Value( int colIndex,unsigned __int64& val )
{
	//check if the column index exists
	std::map<ub4,ColumnInfo*>::const_iterator iterInfo = m_ColInfoMapByPos.find(colIndex);
	if (iterInfo==m_ColInfoMapByPos.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	if(iterInfo->second->bIsIOVCol)//this column is IOV column
	{
		return false;//ID value cannot be IOV column
	}
	
	FMDBColumn *pCol=nullptr;
	std::map<ub4,FMDBColumn*>::const_iterator iter1=m_ColumnMapByPos.find(colIndex);
	if (iter1==m_ColumnMapByPos.end())
	{
		return false;
	}

	pCol=iter1->second;

	if(pCol->GetType()!=SQLT_VNU)
	{
		return false;//id value should be number
	}

	if (pCol->GetIndicator()[m_CacheRowNumber-1]==-1)
	{
		return false;//null value returns false and do not change the val
	}
	
	return DBTOOLS::ConvertNumberToInt(m_pErr,(OCINumber*)pCol->GetStorage()+(m_CacheRowNumber-1),sizeof(unsigned __int64),false,&val);
}

 bool FMDBRecordSet::GetIntValue( CString ColName,int& val)
 {
	 //check if the column name exists
	 std::map<CString,ColumnInfo*>::const_iterator iter = m_ColInfoMapByName.find(ColName);
	 if (iter==m_ColInfoMapByName.end())
	 {
		 return false;//if the column doesn't exist then return nothing
	 }

	 return GetIntValue(iter->second->Position,val);
 }

 bool FMDBRecordSet::GetIntValue( int colIndex,int& val)
 {
	 //check if the column index exists
	 std::map<ub4,ColumnInfo*>::const_iterator iterInfo = m_ColInfoMapByPos.find(colIndex);
	 if (iterInfo==m_ColInfoMapByPos.end())
	 {
		 return false;//if the column doesn't exist then return nothing
	 }

	 if(iterInfo->second->bIsIOVCol)//this column is IOV column
	 {
		 return false;//int value cannot be IOV column
	 }

	 FMDBColumn *pCol=nullptr;
	 std::map<ub4,FMDBColumn*>::const_iterator iter1=m_ColumnMapByPos.find(colIndex);
	 if (iter1==m_ColumnMapByPos.end())
	 {
		 return false;
	 }

	 pCol=iter1->second;

	 if (pCol->GetIndicator()[m_CacheRowNumber-1]==-1)
	 {
		 return false;//null value, do not change val
	 }

	if(pCol->GetType()==SQLT_VNU)
	{
		return DBTOOLS::ConvertNumberToInt(m_pErr,(OCINumber*)pCol->GetStorage()+(m_CacheRowNumber-1),sizeof(int),true,&val);
	}
	else
	{
		val=*((int*)pCol->GetStorage()+(m_CacheRowNumber-1));//??? is this right?
		return true;
	}
 }

 bool FMDBRecordSet::GetShortValue( int colIndex,short& val )
 {
	 //check if the column index exists
	 std::map<ub4,ColumnInfo*>::const_iterator iterInfo = m_ColInfoMapByPos.find(colIndex);
	 if (iterInfo==m_ColInfoMapByPos.end())
	 {
		 return false;//if the column doesn't exist then return nothing
	 }

	 if(iterInfo->second->bIsIOVCol)//this column is IOV column
	 {
		 return false;//int value cannot be IOV column
	 }

	 FMDBColumn *pCol=nullptr;
	 std::map<ub4,FMDBColumn*>::const_iterator iter1=m_ColumnMapByPos.find(colIndex);
	 if (iter1==m_ColumnMapByPos.end())
	 {
		 return false;
	 }

	 pCol=iter1->second;

	 if (pCol->GetIndicator()[m_CacheRowNumber-1]==-1)
	 {
		 return false;//null value, do not change val
	 }

	 if(pCol->GetType()==SQLT_VNU)
	 {
		 return DBTOOLS::ConvertNumberToInt(m_pErr,(OCINumber*)pCol->GetStorage()+(m_CacheRowNumber-1),sizeof(short),true,&val);
	 }
	 else
	 {
		 val=*((int*)pCol->GetStorage()+(m_CacheRowNumber-1));//??? is this right?
		 return true;
	 }
 }

 bool FMDBRecordSet::GetShortValue( CString ColName,short& val )
 {
	 //check if the column name exists
	 std::map<CString,ColumnInfo*>::const_iterator iter = m_ColInfoMapByName.find(ColName);
	 if (iter==m_ColInfoMapByName.end())
	 {
		 return false;//if the column doesn't exist then return nothing
	 }

	 return GetShortValue(iter->second->Position,val);
 }

bool FMDBRecordSet::GetDoubleValue( CString ColName,double& val )
{
	//check if the column name exists
	std::map<CString,ColumnInfo*>::const_iterator iter = m_ColInfoMapByName.find(ColName);
	if (iter==m_ColInfoMapByName.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	return GetDoubleValue(iter->second->Position,val);
}

bool FMDBRecordSet::GetDoubleValue( int colIndex,double& val )
{
	//if the value is empty
	if(IsEmptyValue(colIndex))
	{
		val=0.000000001;
		return true;
	}

	//check if the column index exists
	std::map<ub4,ColumnInfo*>::const_iterator iterInfo = m_ColInfoMapByPos.find(colIndex);
	if (iterInfo==m_ColInfoMapByPos.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	if(iterInfo->second->bIsIOVCol)//this column is IOV column
	{
		return false;//int value cannot be IOV column
	}

	FMDBColumn *pCol=nullptr;
	std::map<ub4,FMDBColumn*>::const_iterator iter1=m_ColumnMapByPos.find(colIndex);
	if (iter1==m_ColumnMapByPos.end())
	{
		return false;
	}


	pCol=iter1->second;

	if(pCol->GetType()==SQLT_VNU)
	{
		return DBTOOLS::ConvertNumberToDouble(m_pErr,(OCINumber*)pCol->GetStorage()+(m_CacheRowNumber-1),sizeof(double),&val);
	}
	else
	{
		val=*((double*)pCol->GetStorage()+(m_CacheRowNumber-1));//??? is this right?
		return true;
	}
}

bool FMDBRecordSet::IsEmptyValue( CString ColName )
{
	//check if the column name exists
	std::map<CString,ColumnInfo*>::const_iterator iter = m_ColInfoMapByName.find(ColName);
	if (iter==m_ColInfoMapByName.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	return IsEmptyValue(iter->second->Position);
}

bool FMDBRecordSet::IsEmptyValue( int ColIndex )
{
	//check if the column index exists
	std::map<ub4,ColumnInfo*>::const_iterator iterInfo = m_ColInfoMapByPos.find(ColIndex);
	if (iterInfo==m_ColInfoMapByPos.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	if(iterInfo->second->bIsIOVCol)//this column is IOV column
	{
		FMDBIOVColumn *pCol=NULL;
		std::map<ub4,FMDBIOVColumn*>::const_iterator iter=m_IOVColumnMapByPos.find(ColIndex);
		if (iter==m_IOVColumnMapByPos.end())
		{
			ASSERT(FALSE);//,_T("column id does not exist"));
			return false;
		}

		if(iter->second->GetIndicator()[iterInfo->second->ColumnID]==-1)
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	else//this column is simple column
	{
		FMDBColumn *pCol=nullptr;
		std::map<ub4,FMDBColumn*>::const_iterator iter=m_ColumnMapByPos.find(ColIndex);
		if (iter==m_ColumnMapByPos.end())
		{
			ASSERT(FALSE);//,_T("column id does not exist"));
			return false;
		}

		if(iter->second->GetIndicator()[m_CacheRowNumber-1]==-1)
		{
			return true;
		}
		else
		{
			return false;
		}

	}
}

bool FMDBRecordSet::GetString( CString ColName,CString& val )
{
	//check if the column name exists
	std::map<CString,ColumnInfo*>::const_iterator iter = m_ColInfoMapByName.find(ColName);
	if (iter==m_ColInfoMapByName.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	return GetString(iter->second->Position,val);
}

bool FMDBRecordSet::GetString( int colIndex,CString& val )
{
	//check if the column index exists
	std::map<ub4,ColumnInfo*>::const_iterator iterInfo = m_ColInfoMapByPos.find(colIndex);
	if (iterInfo==m_ColInfoMapByPos.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	if(iterInfo->second->bIsIOVCol==false)//this column is not IOV column
	{
		return false;//text must be IOV column
	}

	FMDBIOVColumn *pCol=nullptr;
	std::map<ub4,FMDBIOVColumn*>::const_iterator iter1=m_IOVColumnMapByPos.find(colIndex);
	if (iter1==m_IOVColumnMapByPos.end())
	{
		return false;
	}


	pCol=iter1->second;

	char* pStr=(char*)((OCIIOV*)pCol->GetStorage())[m_CacheRowNumber-1].bfp;

	val.GetBufferSetLength(((OCIIOV*)pCol->GetStorage())[m_CacheRowNumber-1].bfl/sizeof(TCHAR));
	memcpy(val.GetBuffer(),((OCIIOV*)pCol->GetStorage())[m_CacheRowNumber-1].bfp,((OCIIOV*)pCol->GetStorage())[m_CacheRowNumber-1].bfl);
	val.ReleaseBuffer();
	val.Trim();

	return true;
}

bool FMDBRecordSet::GetInt64Value( int colIndex,__int64& val )
{
	//check if the column index exists
	std::map<ub4,ColumnInfo*>::const_iterator iterInfo = m_ColInfoMapByPos.find(colIndex);
	if (iterInfo==m_ColInfoMapByPos.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	if(iterInfo->second->bIsIOVCol)//this column is IOV column
	{
		return false;//ID value cannot be IOV column
	}

	FMDBColumn *pCol=nullptr;
	std::map<ub4,FMDBColumn*>::const_iterator iter1=m_ColumnMapByPos.find(colIndex);
	if (iter1==m_ColumnMapByPos.end())
	{
		return false;
	}

	pCol=iter1->second;

	if(pCol->GetType()!=SQLT_VNU)
	{
		return false;//id value should be number
	}
	if (pCol->GetIndicator()[m_CacheRowNumber-1]==-1)
	{
		return false;//null value, do not change val
	}
	return DBTOOLS::ConvertNumberToInt(m_pErr,(OCINumber*)pCol->GetStorage()+(m_CacheRowNumber-1),sizeof(__int64),true,&val);

}

bool FMDBRecordSet::GetInt64Value( CString ColName, __int64& val )
{
	//check if the column name exists
	std::map<CString,ColumnInfo*>::const_iterator iter = m_ColInfoMapByName.find(ColName);
	if (iter==m_ColInfoMapByName.end())
	{
		return false;//if the column doesn't exist then return nothing
	}

	return GetInt64Value(iter->second->Position,val);
}


void FMDBRecordSet::ResetIOVColumnValue()
{
	//clear cache data before fetch data to the cache
	for (std::map<ub4,FMDBIOVColumn*>::iterator iter=m_IOVColumnMapByPos.begin();iter!=m_IOVColumnMapByPos.end();iter++)
	{
		iter->second->ResetStorage();
	}
}

int FMDBRecordSet::GetRowStorageSize()
{
	ub4 nSize=0;
	for ( std::map<ub4,ColumnInfo*>::const_iterator iter=m_ColInfoMapByPos.begin();iter!=m_ColInfoMapByPos.end();iter++)
	{
		nSize+=iter->second->MaxSize;
	}
	
	return (int)nSize;
}





















